import urllib2
import httplib
import re
import sys

from APIExceptions import *
from ResponseData import *

if sys.version_info[:2] > (2, 4): # pragma: no cover
    from urllib2 import quote
else:
    from urllib import quote

class APIwrapper(object):
    """
    Abstract class for API handler,providing the key functions of a wrapper of website API.
    """
    keywords={}
    reserved=Set(['proxy'])
    host=''
    joinCharacter="%20"
    def __init__(self):
        """
        create the handler
        """
        self.requestContext={}
        self.METHOD='GET'
        self.META={}
        
    def setupParameters(self,parameters):
        """
        setup the request Context
        """
        for key in parameters:
            self.requestContext[key]=parameters[key]
            
    def setupMeta(self,parameters):
        """
        Setup the request header.
        """
        for key in parameters:
            self.META[key]=parameters[key]
            
    def sendRequest(self,parameters,method='GET'):
        """
        send request and return the result as json object
        """
        response=self.getRaw(self.getBaseUrl()+self.getQueryUrl(parameters),method)
        if response['header'] == None:
            errorMsg=etree.fromstring(response['body'])
            #print errorMsg.find('Code')
            # TODO raise HTTP404Exception ... instead?
            raise Exception(response['body'])
        type=response['header'].gettype()
        if type=='text/html':
            return DataNode(response['body'])
        elif type=='text/xml':
            return DataNode(response['body'])
        elif type=='text/json':
            return response['body']
        #return response
    def getRaw(self,url,method='GET',body=''):
        """
        Get Raw data from 
        """
        response={}
        if "proxy" in self.requestContext:
            host=self.requestContext["proxy_host_"+self.requestContext["proxy"]]
            user=self.requestContext["proxy_user_"+self.requestContext["proxy"]]
            password=self.requestContext["prox_password_"+self.requestContext["proxy"]]
            proxy = urllib2.ProxyHandler({'http': 'http://'+user+':'+password+'@'+host})
            auth = urllib2.HTTPBasicAuthHandler()
            opener = urllib2.build_opener(proxy, auth, urllib2.HTTPHandler)
            urllib2.install_opener(opener)
        try:
            req = urllib2.Request(url,headers=self.META) 
            query=urllib2.urlopen(req)
            response['header']=query.info()
            response['body']=query.read()
        except urllib2.HTTPError, e:
            response['header']=None
            response['error_code']=e.code
            response['body']=e.fp.read()
        return response
    def getBaseUrl(self):
        return ''.join(self.host)
    def getQueryUrl(self,parameters={},sort=True):
        #if given parameters, add the parameter into request context 
        if not type(parameters) is dict:
            raise Exception('Parameters should be dictionary!')
        cmd=[]
        if not hasattr(self,'requestContext'):
            raise "Haven't set up the context for the request!"
        for key in self.requestContext:
            parameters[key]=self.requestContext[key]
        if sort:
            keys=parameters.keys()
            keys.sort()
        else:
            keys=parameters.keys()
        for key in keys:
            if key in self.keywords:
                cmd.append(self.keywords[key]+'='+self.toUrl(parameters[key]))
            else:
                cmd.append(key+'='+self.toUrl(parameters[key]))
        return '&'.join(cmd)
    def clear(self,exceptkey={}):
        for key in self.requestContext.keys():
            if not (key in self.reserved) or not (key in exceptkey):
                del self.requestContext[key]
    # shortcuts    
    def next(self):
        self.currentPage+=self.currentPageSize
        return self.sendRequest({self.pagestart:self.currentPage})
    # TODO need to define
    def get(self,parameters):
        pass
    def post(self,parameters):
        pass
    
    #helpers
    def getCurrentContext(self):
        """
        For debug use. 
        """
        return self.requestContext
    def toUrl(self,string):
        """
        urlize the string
        """
        string=str(string)
       # string=self.joinCharacter.join(re.findall(r"\S+",string))
        return quote(unicode(string)
                        .encode('utf-8'),safe='~')
